/*
 *  Copyright (C) 2025 Andrés Martínez Mera - andresmmera@protonmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "polarplotwidget.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <cmath>

PolarPlotWidget::PolarPlotWidget(QWidget* parent)
    : QWidget(parent), fMin(1e20), fMax(-1) {
  // Initialize the QCustomPlot widget
  plot = new QCustomPlot(this);
  plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

  // Clear default plot layout and set up polar plot
  plot->plotLayout()->clear();

  // Create angular axis and add to layout
  angularAxis = new QCPPolarAxisAngular(plot);
  plot->plotLayout()->addElement(0, 0, angularAxis);

  // Get the radial axis from angular axis
  radialAxis = angularAxis->radialAxis();

  // Configure angular axis (angle lines)
  angularAxis->setRange(0, 360);
  angularAxis->setRangeDrag(false);
  angularAxis->setTickLabelMode(QCPPolarAxisAngular::lmUpright);

  // Configure radial axis (concentric circles)
  radialAxis->setRange(0, 1.0);
  radialAxis->setTickLabelMode(QCPPolarAxisRadial::lmUpright);
  radialAxis->setTickLabelRotation(0);
  radialAxis->setAngle(45);

  // Configure grid
  angularAxis->grid()->setAngularPen(
      QPen(QColor(200, 200, 200), 1, Qt::SolidLine));
  angularAxis->grid()->setRadialPen(
      QPen(QColor(200, 200, 200), 1, Qt::SolidLine));
  angularAxis->grid()->setSubGridType(QCPPolarGrid::gtAll);

  // Set up the frequency units
  frequencyUnits << "Hz" << "kHz" << "MHz" << "GHz";

  // Clear containers
  markerItems.clear();
  markerLabels.clear();
  traceGraphs.clear();

  // Create the main layout
  QVBoxLayout* mainLayout = new QVBoxLayout(this);
  mainLayout->addWidget(plot);

  // Add the axis settings layout
  mainLayout->addLayout(setupAxisSettings());
  setLayout(mainLayout);

  // Configure radial axis
  radialAxis->setRange(0, 1.0);
  radialAxis->setTickLabelMode(QCPPolarAxisRadial::lmUpright);
  radialAxis->setTickLabelRotation(0);
  radialAxis->setAngle(45);

  // Connect range change signals to update the widgets
  connect(plot, &QCustomPlot::mouseMove, this,
          static_cast<void (PolarPlotWidget::*)(QMouseEvent*)>(
              &PolarPlotWidget::checkAxisRanges));
  connect(plot, &QCustomPlot::mouseRelease, this,
          static_cast<void (PolarPlotWidget::*)(QMouseEvent*)>(
              &PolarPlotWidget::checkAxisRanges));
  connect(plot, &QCustomPlot::afterReplot, this,
          static_cast<void (PolarPlotWidget::*)()>(
              &PolarPlotWidget::checkAxisRanges));
  connect(radialAxis,
          QOverload<const QCPRange&>::of(&QCPPolarAxisRadial::rangeChanged),
          this, &PolarPlotWidget::onRadialRangeChanged);

  // Initial plot update
  plot->replot();
}

PolarPlotWidget::~PolarPlotWidget() {
  // Clean up any remaining graphics items
  clearGraphicsItems();

  // QCustomPlot will handle cleanup of its own objects
}

void PolarPlotWidget::addTrace(const QString& name, const Trace& trace) {
  traces[name] = trace;
  updateFrequencyRange(); // Update frequency range based on new trace
  updatePlot();
}

void PolarPlotWidget::updateFrequencyRange() {
  fMin = 1e20;
  fMax = -1;

  for (const auto& trace : traces) {
    if (!trace.frequencies.isEmpty()) {
      double traceMinFreq = trace.frequencies.first();
      double traceMaxFreq = trace.frequencies.last();

      if (traceMinFreq < fMin) {
        fMin = traceMinFreq;
      }
      if (traceMaxFreq > fMax) {
        fMax = traceMaxFreq;
      }
    }
  }

  // Update spin box values
  double freqMultiplier = getFrequencyMultiplier();
  fMinSpinBox->setValue(fMin / freqMultiplier);
  fMinSpinBox->setMinimum(fMin / freqMultiplier);

  fMaxSpinBox->setValue(fMax / freqMultiplier);
  fMaxSpinBox->setMaximum(fMax / freqMultiplier);
}

void PolarPlotWidget::removeTrace(const QString& name) {
  traces.remove(name);

  // Remove associated polar graphs if they exist
  if (traceGraphs.contains(name)) {
    for (QCPPolarGraph* graph : traceGraphs[name]) {
      angularAxis->removeGraph(graph);
    }
    traceGraphs.remove(name);
  }
  updatePlot();
}

void PolarPlotWidget::clearTraces() {
  traces.clear();

  // Clear all polar graphs
  for (auto& graphList : traceGraphs) {
    for (QCPPolarGraph* graph : graphList) {
      angularAxis->removeGraph(graph);
    }
  }
  traceGraphs.clear();

  updatePlot();
}

QPen PolarPlotWidget::getTracePen(const QString& traceName) const {
  if (traces.contains(traceName)) {
    return traces[traceName].pen;
  }
  return QPen();
}

void PolarPlotWidget::setTracePen(const QString& traceName, const QPen& pen) {
  if (traces.contains(traceName)) {
    traces[traceName].pen = pen;
    updatePlot();
  }
}

QMap<QString, QPen> PolarPlotWidget::getTracesInfo() const {
  QMap<QString, QPen> penMap;
  for (auto it = traces.constBegin(); it != traces.constEnd(); ++it) {
    penMap.insert(it.key(), it.value().pen);
  }
  return penMap;
}

bool PolarPlotWidget::addMarker(const QString& markerId, double frequency,
                                const QPen& pen) {
  if (markers.contains(markerId)) {
    return false;
  }

  bool frequencyInRange = false;
  for (auto it = traces.constBegin(); it != traces.constEnd(); ++it) {
    const Trace& trace = it.value();
    if (!trace.frequencies.isEmpty() &&
        frequency >= trace.frequencies.first() &&
        frequency <= trace.frequencies.last()) {
      frequencyInRange = true;
      break;
    }
  }

  if (!frequencyInRange) {
    return false;
  }

  Marker marker;
  marker.id        = markerId;
  marker.frequency = frequency;
  marker.pen       = pen;

  markers.insert(markerId, marker);
  updatePlot();
  return true;
}

bool PolarPlotWidget::removeMarker(const QString& markerId) {
  if (!markers.contains(markerId)) {
    return false;
  }

  markers.remove(markerId);
  updatePlot();
  return true;
}

void PolarPlotWidget::clearMarkers() {
  markers.clear();
  updatePlot();
}

QMap<QString, double> PolarPlotWidget::getMarkers() const {
  QMap<QString, double> markerFrequencies;
  for (auto it = markers.constBegin(); it != markers.constEnd(); ++it) {
    markerFrequencies.insert(it.key(), it.value().frequency);
  }
  return markerFrequencies;
}

void PolarPlotWidget::updatePlot() {
  clearGraphicsItems();

  // Remove existing polar graphs
  for (auto& graphList : traceGraphs) {
    for (QCPPolarGraph* graph : graphList) {
      angularAxis->removeGraph(graph);
    }
  }
  traceGraphs.clear();

  const double PHASE_WRAP_THRESHOLD = 180.0; // Degrees

  for (auto it = traces.constBegin(); it != traces.constEnd(); ++it) {
    const QString& name = it.key();
    const Trace& trace  = it.value();

    QList<QCPPolarGraph*> graphsForTrace;

    // Create initial polar graph for this trace
    QCPPolarGraph* currentGraph = new QCPPolarGraph(angularAxis, radialAxis);
    currentGraph->setPen(trace.pen);
    currentGraph->setName(name);
    graphsForTrace.append(currentGraph);

    double prevPhase = -1e3; // Initialize with impossible value

    for (int i = 0; i < trace.values.size() && i < trace.frequencies.size();
         ++i) {
      double frequency = trace.frequencies[i];
      if (frequency >= fMin && frequency <= fMax) {
        std::complex<double> value = trace.values[i];
        double magnitude           = std::abs(value);
        double phase               = std::arg(value) * 180.0 / M_PI;
        if (phase < 0) {
          phase += 360;
        }

        // Check for phase wrap (only after first point)
        if (prevPhase != -1e3 &&
            std::abs(phase - prevPhase) > PHASE_WRAP_THRESHOLD) {
          // Create new polar graph for next segment
          currentGraph = new QCPPolarGraph(angularAxis, radialAxis);
          currentGraph->setPen(trace.pen);
          currentGraph->setName(name);
          graphsForTrace.append(currentGraph);
        }

        // Add data point to current graph
        currentGraph->addData(phase, magnitude);
        prevPhase = phase;
      }
    }

    // Store all graphs for this trace
    traceGraphs[name] = graphsForTrace;
  }

  drawCustomMarkers();
  plot->replot();
}

void PolarPlotWidget::updateRAxis() {
  double rMin =
      qMax(0.0, rAxisMin->value()); // Ensure minimum is not less than 0
  double rMax = rAxisMax->value();

  // Ensure max is greater than min
  if (rMax <= rMin) {
    rMax = rMin + 0.1;
    rAxisMax->blockSignals(true);
    rAxisMax->setValue(rMax);
    rAxisMax->blockSignals(false);
  }

  // Update the spin box if we had to correct the minimum
  if (rMin != rAxisMin->value()) {
    rAxisMin->blockSignals(true);
    rAxisMin->setValue(rMin);
    rAxisMin->blockSignals(false);
  }

  radialAxis->setRange(rMin, rMax);
  updatePlot();
}

void PolarPlotWidget::updateAngleAxis() {
  // Angular axis is typically fixed at 360 degrees
  updatePlot();
}

void PolarPlotWidget::toggleDisplayMode() {
  updatePlot();
}

bool PolarPlotWidget::updateMarkerFrequency(const QString& markerId,
                                            double newFrequency) {
  // Check if marker exists
  if (!markers.contains(markerId)) {
    return false;
  }

  // Check if any trace contains this frequency
  bool frequencyInRange = false;
  for (auto it = traces.constBegin(); it != traces.constEnd(); ++it) {
    const Trace& trace = it.value();
    if (!trace.frequencies.isEmpty() &&
        newFrequency >= trace.frequencies.first() &&
        newFrequency <= trace.frequencies.last()) {
      frequencyInRange = true;
      break;
    }
  }

  if (!frequencyInRange) {
    return false;
  }

  // Update the marker's frequency
  markers[markerId].frequency = newFrequency;

  // Trigger repaint
  updatePlot();
  return true;
}

void PolarPlotWidget::clearGraphicsItems() {
  // Remove all marker items
  for (QCPItemEllipse* item : markerItems) {
    plot->removeItem(item);
  }
  markerItems.clear();

  // Remove all marker labels
  for (QCPItemText* label : markerLabels) {
    plot->removeItem(label);
  }
  markerLabels.clear();
}

QGridLayout* PolarPlotWidget::setupAxisSettings() {
  QGridLayout* axisLayout = new QGridLayout();

  fMin = 1e20;
  fMax = -1;

  QLabel* FreqLabel = new QLabel("<b>Frequency</b>");
  axisLayout->addWidget(FreqLabel, 0, 0);

  // Create frequency controls
  fMinSpinBox = new QDoubleSpinBox;
  fMinSpinBox->setRange(0, 1e12);
  fMinSpinBox->setSingleStep(10);
  connect(fMinSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
          this, &PolarPlotWidget::onFMinChanged);
  axisLayout->addWidget(fMinSpinBox, 0, 1);

  fMaxSpinBox = new QDoubleSpinBox;
  fMaxSpinBox->setRange(0, 1e12);
  fMaxSpinBox->setSingleStep(10);
  connect(fMaxSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
          this, &PolarPlotWidget::onFMaxChanged);
  axisLayout->addWidget(fMaxSpinBox, 0, 2);

  fUnitComboBox = new QComboBox;
  fUnitComboBox->addItems(frequencyUnits);
  fUnitComboBox->setCurrentIndex(2); // MHz
  connect(fUnitComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
          this, &PolarPlotWidget::onFUnitChanged);
  axisLayout->addWidget(fUnitComboBox, 0, 3);

  // Radius axis settings
  QLabel* rAxisLabel = new QLabel("<b>Radius</b>");
  axisLayout->addWidget(rAxisLabel, 1, 0);

  rAxisMin = new QDoubleSpinBox();
  rAxisMin->setMinimum(0.0); // Ensure minimum cannot be set below 0
  rAxisMin->setMaximum(1000000);
  rAxisMin->setValue(0.0);
  rAxisMin->setDecimals(2);
  rAxisMin->setSingleStep(0.1);
  connect(rAxisMin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
          &PolarPlotWidget::updateRAxis);
  axisLayout->addWidget(rAxisMin, 1, 1);

  rAxisMax = new QDoubleSpinBox();
  rAxisMax->setMinimum(0.1); // Ensure maximum is always positive
  rAxisMax->setMaximum(1000000);
  rAxisMax->setValue(1.0);
  rAxisMax->setDecimals(2);
  rAxisMax->setSingleStep(0.1);
  connect(rAxisMax, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
          &PolarPlotWidget::updateRAxis);
  axisLayout->addWidget(rAxisMax, 1, 2);

  rAxisDiv = new QDoubleSpinBox();
  rAxisDiv->setMinimum(0.1);
  rAxisDiv->setMaximum(1000000);
  rAxisDiv->setValue(0.2);
  rAxisDiv->setDecimals(2);
  rAxisDiv->setSingleStep(0.1);
  connect(rAxisDiv, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
          &PolarPlotWidget::updateRAxis);
  axisLayout->addWidget(rAxisDiv, 1, 3);

  // Display mode
  QLabel* modeLabel = new QLabel("<b>Marker format</b>");
  axisLayout->addWidget(modeLabel, 2, 0);

  displayModeCombo = new QComboBox();
  displayModeCombo->addItem("Magnitude/Phase");
  displayModeCombo->addItem("Real/Imaginary");
  connect(displayModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
          this, &PolarPlotWidget::toggleDisplayMode);
  axisLayout->addWidget(displayModeCombo, 2, 1, 1, 2);

  return axisLayout;
}

double PolarPlotWidget::getRmax() {
  return rAxisMax->value();
}

double PolarPlotWidget::getRmin() {
  return rAxisMin->value();
}

double PolarPlotWidget::getRdiv() {
  return rAxisDiv->value();
}

int PolarPlotWidget::getDisplayMode() const {
  return displayModeCombo->currentIndex();
}

std::complex<double>
PolarPlotWidget::getComplexValueAtFrequency(const Trace& trace,
                                            double frequency) {
  // Find the closest frequency points in the trace
  int lowerIndex = -1;
  for (int i = 0; i < trace.frequencies.size() - 1; ++i) {
    if (trace.frequencies[i] <= frequency &&
        frequency <= trace.frequencies[i + 1]) {
      lowerIndex = i;
      break;
    }
  }

  // If we found an interval containing the marker frequency
  if (lowerIndex >= 0) {
    // Linear interpolation to find the complex value at marker frequency
    double f1               = trace.frequencies[lowerIndex];
    double f2               = trace.frequencies[lowerIndex + 1];
    std::complex<double> v1 = trace.values[lowerIndex];
    std::complex<double> v2 = trace.values[lowerIndex + 1];

    // Linear interpolation formula applied to both real and imaginary parts
    double t    = (frequency - f1) / (f2 - f1);
    double real = v1.real() + t * (v2.real() - v1.real());
    double imag = v1.imag() + t * (v2.imag() - v1.imag());

    return std::complex<double>(real, imag);
  }

  // If frequency is exactly at the first or last point
  if (std::abs(frequency - trace.frequencies.first()) < 1e-10 &&
      !trace.values.isEmpty()) {
    return trace.values.first();
  }
  if (std::abs(frequency - trace.frequencies.last()) < 1e-10 &&
      !trace.values.isEmpty()) {
    return trace.values.last();
  }

  // Return zero if not found (shouldn't happen if checks are proper)
  return std::complex<double>(0, 0);
}

std::complex<double>
PolarPlotWidget::convertToDisplayFormat(const std::complex<double>& value,
                                        int mode) {
  if (mode == 0) {
    // Magnitude/Phase - already handled in plotting function
    return value;
  } else {
    // Real/Imaginary - also handled in plotting function
    return value;
  }
}

void PolarPlotWidget::drawCustomMarkers() {
  if (markers.isEmpty() || traces.isEmpty()) {
    return;
  }

  // Clear existing marker graphics items
  clearGraphicsItems();

  // Iterate through each trace
  for (auto traceIt = traces.constBegin(); traceIt != traces.constEnd();
       ++traceIt) {
    const QString& traceName = traceIt.key();
    const Trace& trace       = traceIt.value();

    // Skip traces with no frequency data
    if (trace.frequencies.isEmpty() || trace.values.isEmpty()) {
      continue;
    }

    // Draw markers for this trace
    for (auto markerIt = markers.constBegin(); markerIt != markers.constEnd();
         ++markerIt) {
      const QString& markerId = markerIt.key();
      const Marker& marker    = markerIt.value();
      double markerFreq       = marker.frequency;

      // Check if marker frequency is within the trace frequency range
      if (markerFreq < trace.frequencies.first() ||
          markerFreq > trace.frequencies.last()) {
        continue;
      }

      // Get interpolated complex value at marker frequency
      std::complex<double> value =
          getComplexValueAtFrequency(trace, markerFreq);

      // Convert to display format based on current mode
      double angle, radius;
      int displayMode = displayModeCombo->currentIndex();

      if (displayMode == 0) {
        // Magnitude/Phase mode
        radius = std::abs(value);
        angle  = std::arg(value) * 180.0 / M_PI;
        if (angle < 0) {
          angle += 360;
        }
      } else {
        // Real/Imaginary mode
        angle = std::atan2(value.imag(), value.real()) * 180.0 / M_PI;
        if (angle < 0) {
          angle += 360;
        }
        radius = std::sqrt(value.real() * value.real() +
                           value.imag() * value.imag());
      }

      // Create a marker point using QCPItemEllipse
      QCPItemEllipse* markerPoint = new QCPItemEllipse(plot);

      // Set position using polar coordinates - QCustomPlot handles the
      // conversion
      double angleRad = angle * M_PI / 180.0;
      double xTopLeft = radius * cos(angleRad);
      double yTopLeft = radius * sin(angleRad);

      double xBottomRight = (radius - 0.02) * cos((angle + 2) * M_PI / 180.0);
      double yBottomRight = (radius - 0.02) * sin((angle + 2) * M_PI / 180.0);

      markerPoint->topLeft->setType(QCPItemPosition::ptPlotCoords);
      markerPoint->topLeft->setCoords(xTopLeft, yTopLeft);

      markerPoint->bottomRight->setType(QCPItemPosition::ptPlotCoords);
      markerPoint->bottomRight->setCoords(xBottomRight, yBottomRight);

      // Set marker appearance
      markerPoint->setPen(marker.pen);
      markerPoint->setBrush(QBrush(marker.pen.color()));

      markerItems.append(markerPoint);

      // Determine frequency unit and scaling
      QString freqUnit = "Hz";
      double freqValue = markerFreq;
      if (markerFreq >= 1e9) {
        freqUnit  = "GHz";
        freqValue = markerFreq / 1e9;
      } else if (markerFreq >= 1e6) {
        freqUnit  = "MHz";
        freqValue = markerFreq / 1e6;
      } else if (markerFreq >= 1e3) {
        freqUnit  = "kHz";
        freqValue = markerFreq / 1e3;
      }

      // Create label with marker ID, value, and frequency
      QString labelText;
      if (displayMode == 0) {
        // Magnitude/Phase format
        labelText = QString("%1 [%2]: %3 %4\n%5∠%6°")
                        .arg(markerId)
                        .arg(traceName)
                        .arg(freqValue, 0, 'g', 3)
                        .arg(freqUnit)
                        .arg(radius, 0, 'f', 2)
                        .arg(angle, 0, 'f', 2);
      } else {
        // Real/Imaginary format
        labelText = QString("%1 [%2]: %3 %4\n%5%6j%7")
                        .arg(markerId)
                        .arg(traceName)
                        .arg(freqValue, 0, 'g', 3)
                        .arg(freqUnit)
                        .arg(value.real(), 0, 'f', 2)
                        .arg(value.imag() >= 0 ? "+" : "")
                        .arg(value.imag(), 0, 'f', 2);
      }

      // Create and position the label using QCPItemText
      QCPItemText* markerLabel = new QCPItemText(plot);

      double xLabel = radius * cos(angleRad);
      double yLabel = radius * sin(angleRad);

      markerLabel->position->setType(QCPItemPosition::ptPlotCoords);
      markerLabel->position->setCoords(xLabel, yLabel + 0.1);

      markerLabel->setText(labelText);
      markerLabel->setFont(QFont("Arial", 9, QFont::Bold));
      markerLabel->setColor(Qt::black);
      markerLabel->setBrush(QBrush(QColor(255, 255, 255, 200)));
      markerLabel->setPen(QPen(Qt::black));
      markerLabel->setPadding(QMargins(6, 6, 6, 6));

      markerLabels.append(markerLabel);
    }
  }
}

void PolarPlotWidget::onFMinChanged(double value) {
  fMin = value * getFrequencyMultiplier();
  updatePlot();
}

void PolarPlotWidget::onFMaxChanged(double value) {
  fMax = value * getFrequencyMultiplier();
  updatePlot();
}

void PolarPlotWidget::onFUnitChanged() {
  fMin = fMinSpinBox->value() * getFrequencyMultiplier();
  fMax = fMaxSpinBox->value() * getFrequencyMultiplier();
  updatePlot();
}

double PolarPlotWidget::getFrequencyMultiplier() const {
  int index = fUnitComboBox->currentIndex();
  switch (index) {
  case 0:
    return 1.0; // Hz
  case 1:
    return 1e3; // kHz
  case 2:
    return 1e6; // MHz
  case 3:
    return 1e9; // GHz
  default:
    return 1.0;
  }
}

void PolarPlotWidget::onRadialRangeChanged(const QCPRange& newRange) {
  // If the lower bound is negative, correct it
  if (newRange.lower < 0.0) {
    double shift = -newRange.lower;
    QCPRange correctedRange(0.0, newRange.upper + shift);

    // Temporarily disconnect to avoid infinite recursion
    disconnect(
        radialAxis,
        QOverload<const QCPRange&>::of(&QCPPolarAxisRadial::rangeChanged), this,
        &PolarPlotWidget::onRadialRangeChanged);

    // Set the corrected range
    radialAxis->setRange(correctedRange);

    // Reconnect
    connect(radialAxis,
            QOverload<const QCPRange&>::of(&QCPPolarAxisRadial::rangeChanged),
            this, &PolarPlotWidget::onRadialRangeChanged);

    // Update the spin boxes
    rAxisMin->blockSignals(true);
    rAxisMin->setValue(0.0);
    rAxisMin->blockSignals(false);

    rAxisMax->blockSignals(true);
    rAxisMax->setValue(correctedRange.upper);
    rAxisMax->blockSignals(false);
  }
}

// Send settings to the main program
PolarPlotWidget::AxisSettings PolarPlotWidget::getSettings() const {
  AxisSettings settings;
  settings.freqMin  = fMinSpinBox->value();
  settings.freqMax  = fMaxSpinBox->value();
  settings.freqUnit = fUnitComboBox->currentText();

  settings.radius_min = rAxisMin->value();
  settings.radius_max = rAxisMax->value();
  settings.radius_div = rAxisDiv->value();

  settings.marker_format = displayModeCombo->currentText();

  return settings;
}

// Get settings from the main program
void PolarPlotWidget::setSettings(const AxisSettings& settings) {
  fMinSpinBox->setValue(settings.freqMin);
  fMaxSpinBox->setValue(settings.freqMax);
  fUnitComboBox->setCurrentText(settings.freqUnit);

  rAxisMin->setValue(settings.radius_min);
  rAxisMax->setValue(settings.radius_max);
  rAxisDiv->setValue(settings.radius_div);

  displayModeCombo->setCurrentText(settings.marker_format);

  updatePlot();
}

/*
  FUNCTIONS TO UPDATE AXIS SETTING WIDGETS WHEN THE USER PANS OR ZOOMS
 */
void PolarPlotWidget::checkAxisRanges() {
  // Get current radial axis range
  QCPRange radialRange = radialAxis->range();

  // Ensure minimum radius is not less than 0
  double newMin = qMax(0.0, radialRange.lower);
  double newMax = radialRange.upper;

  // If minimum is negative, we need to shift the entire range
  if (radialRange.lower < 0.0) {
    double shift = -radialRange.lower; // Amount to shift up
    newMin       = 0.0;
    newMax       = radialRange.upper + shift;

    // Update the axis with the corrected range
    radialAxis->setRange(newMin, newMax);
    plot->replot();
  }

  // Update the spin boxes without triggering their signals
  if (qAbs(rAxisMin->value() - newMin) > 1e-6) {
    rAxisMin->blockSignals(true);
    rAxisMin->setValue(newMin);
    rAxisMin->blockSignals(false);
  }

  if (qAbs(rAxisMax->value() - newMax) > 1e-6) {
    rAxisMax->blockSignals(true);
    rAxisMax->setValue(newMax);
    rAxisMax->blockSignals(false);
  }
}

void PolarPlotWidget::checkAxisRanges(QMouseEvent* event) {
  // This overload handles mouse events - just call the main function
  Q_UNUSED(event)
  checkAxisRanges();
}
